using RealtimeCollabGame.Application.Commands;
using RealtimeCollabGame.Application.Interfaces;
using RealtimeCollabGame.Application.Queries;
using RealtimeCollabGame.Application.DTOs;
using RealtimeCollabGame.Application.Handlers;

namespace RealtimeCollabGame.Application.Services;

public class GameService
{
    private readonly CreateGameCommandHandler _createGameHandler;
    private readonly JoinGameCommandHandler _joinGameHandler;
    private readonly PaintActionCommandHandler _paintActionHandler;
    private readonly GetGameQueryHandler _getGameHandler;
    private readonly GetGameByCodeQueryHandler _getGameByCodeHandler;
    private readonly GetAllGamesQueryHandler _getAllGamesHandler;
    private readonly DeleteGameCommandHandler _deleteGameHandler;
    private readonly LeaveGameCommandHandler _leaveGameHandler;
    private readonly SetPlayerReadyCommandHandler _setPlayerReadyHandler;
    private readonly StartGameCommandHandler _startGameHandler;

    public GameService(
        CreateGameCommandHandler createGameHandler,
        JoinGameCommandHandler joinGameHandler,
        PaintActionCommandHandler paintActionHandler,
        DeleteGameCommandHandler deleteGameHandler,
        GetGameQueryHandler getGameHandler,
        GetGameByCodeQueryHandler getGameByCodeHandler,
        GetAllGamesQueryHandler getAllGamesHandler,
        LeaveGameCommandHandler leaveGameHandler,
        SetPlayerReadyCommandHandler setPlayerReadyHandler,
        StartGameCommandHandler startGameHandler)
    {
        _createGameHandler = createGameHandler;
        _joinGameHandler = joinGameHandler;
        _paintActionHandler = paintActionHandler;
        _deleteGameHandler = deleteGameHandler;
        _getGameHandler = getGameHandler;
        _getGameByCodeHandler = getGameByCodeHandler;
        _getAllGamesHandler = getAllGamesHandler;
        _leaveGameHandler = leaveGameHandler;
        _setPlayerReadyHandler = setPlayerReadyHandler;
        _startGameHandler = startGameHandler;
    }

    public async Task<GameDto> CreateGameAsync(CreateGameCommand command)
    {
        var game = await _createGameHandler.HandleAsync(command);
        var gameDto = await _getGameHandler.HandleAsync(new GetGameQuery(game.Id));
        return gameDto ?? throw new InvalidOperationException("Failed to retrieve created game");
    }

    public async Task<GameDto> JoinGameAsync(JoinGameCommand command)
    {
        var game = await _joinGameHandler.HandleAsync(command);
        var gameDto = await _getGameHandler.HandleAsync(new GetGameQuery(game.Id));
        return gameDto ?? throw new InvalidOperationException("Failed to retrieve joined game");
    }

    public async Task ProcessPaintActionAsync(PaintActionCommand command)
    {
        await _paintActionHandler.HandleAsync(command);
    }

    public async Task<GameDto?> GetGameAsync(Guid gameId)
    {
        return await _getGameHandler.HandleAsync(new GetGameQuery(gameId));
    }

    public async Task<GameDto?> GetGameByCodeAsync(string code)
    {
        return await _getGameByCodeHandler.HandleAsync(new GetGameByCodeQuery(code));
    }

    public async Task<List<GameDto>> GetAllGamesAsync()
    {
        return await _getAllGamesHandler.HandleAsync(new GetAllGamesQuery());
    }

    public async Task DeleteGameAsync(Guid gameId)
    {
        await _deleteGameHandler.HandleAsync(new DeleteGameCommand(gameId));
    }

    public async Task<GameDto> LeaveGameAsync(LeaveGameCommand command)
    {
        var game = await _leaveGameHandler.HandleAsync(command);
        var gameDto = await _getGameHandler.HandleAsync(new GetGameQuery(game.Id));
        return gameDto ?? throw new InvalidOperationException("Failed to retrieve game after leaving");
    }

    public async Task SetPlayerReadyAsync(Guid gameId, Guid playerId, bool isReady)
    {
        await _setPlayerReadyHandler.HandleAsync(new SetPlayerReadyCommand(gameId, playerId, isReady));
    }

    public async Task StartGameAsync(StartGameCommand command)
    {
        await _startGameHandler.HandleAsync(command);
    }
}